Coverage Report

Created: 2025-05-27 14:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\vk-layer-for-rust\vk-layer-for-rust\vulkan-layer-macros\src\lib.rs
Line
Count
Source
1
// Copyright 2023 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#![warn(missing_docs)]
16
17
//! Macros for `vulkan-layer`.
18
19
use proc_macro::TokenStream;
20
use proc_macro2::TokenStream as TokenStream2;
21
use quote::quote;
22
use syn::{parse_macro_input, ItemImpl, Type};
23
24
mod details;
25
mod dummy;
26
27
/// Derive the implementation of the `vulkan_layer::GlobalHooksInfo` trait from the implementation
28
/// of the `vulkan_layer::GlobalHooks` trait.
29
///
30
/// This attribute macro should be used over an implementation item of the
31
/// `vulkan_layer::GlobalHooks` trait, and will implement the `vulkan_layer::GlobalHooksInfo` trait
32
/// for the type:
33
/// * `GlobalHooksInfo::hooked_commands` returns a list of the overridden methods that appear in the
34
///   implementation item.
35
/// * `GlobalHooksInfo::HooksType` and `GlobalHooksInfo::HooksRefType` are defined as `Self` and
36
///   `&Self`.
37
/// * `GlobalHooksInfo::hooks` returns `self`.
38
///
39
/// # Examples
40
///
41
/// ```
42
/// use ash::vk;
43
/// use vulkan_layer::{
44
///     auto_globalhooksinfo_impl, GlobalHooks, GlobalHooksInfo, LayerResult, LayerVulkanCommand,
45
///     VkLayerInstanceLink,
46
/// };
47
///
48
/// #[derive(Default)]
49
/// struct MyGlobalHooks;
50
///
51
/// #[auto_globalhooksinfo_impl]
52
/// impl GlobalHooks for MyGlobalHooks {
53
///     fn create_instance(
54
///         &self,
55
///         _p_create_info: &vk::InstanceCreateInfo,
56
///         _layer_instance_link: &VkLayerInstanceLink,
57
///         _p_allocator: Option<&vk::AllocationCallbacks>,
58
///         _p_instance: *mut vk::Instance,
59
///     ) -> LayerResult<ash::prelude::VkResult<()>> {
60
///         LayerResult::Unhandled
61
///     }
62
/// }
63
///
64
/// let my_global_hooks: MyGlobalHooks = Default::default();
65
/// assert!(std::ptr::eq(&my_global_hooks, my_global_hooks.hooks()));
66
/// assert_eq!(
67
///     MyGlobalHooks::hooked_commands(),
68
///     [LayerVulkanCommand::CreateInstance]
69
/// );
70
/// ```
71
#[proc_macro_attribute]
72
3
pub fn auto_globalhooksinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream {
73
3
    let original_item: TokenStream2 = item.clone().into();
74
3
    let input = parse_macro_input!(item as ItemImpl);
75
3
    let target_trait = quote!(::vulkan_layer::GlobalHooksInfo);
76
3
    let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| {
77
0
        let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait);
78
0
        let compile_error = e.to_compile_error();
79
0
        quote! {
80
0
            #dummy
81
0
            #compile_error
82
0
        }
83
3
    });
84
3
    quote! {
85
3
        #original_item
86
3
        #to_append
87
3
    }
88
3
    .into()
89
3
}
90
91
/// Derive the implementation of the `vulkan_layer::InstanceInfo` trait from the implementation of
92
/// the `vulkan_layer::InstanceHooks`.
93
///
94
/// This attribute macro should be used over an implementation item of the
95
/// `vulkan_layer::InstanceHooks` trait, and will implement the `vulkan_layer::InstanceInfo` trait
96
/// for the type:
97
/// * `InstanceInfo::hooked_commands` returns a list of the overridden methods that appear in the
98
///   implementation item.
99
/// * `InstanceInfo::HooksType` and `InstanceInfo::HooksRefType` are defined as `Self` and `&Self`.
100
/// * `InstanceInfo::hooks` returns `self`.
101
///
102
/// # Examples
103
///
104
/// ```
105
/// use ash::vk;
106
/// use std::mem::MaybeUninit;
107
/// use vulkan_layer::{
108
///     auto_instanceinfo_impl, InstanceHooks, InstanceInfo, LayerResult, LayerVulkanCommand,
109
/// };
110
///
111
/// #[derive(Default)]
112
/// struct MyInstanceHooks;
113
///
114
/// #[auto_instanceinfo_impl]
115
/// impl InstanceHooks for MyInstanceHooks {
116
///     fn get_physical_device_features(
117
///         &self,
118
///         _physical_device: vk::PhysicalDevice,
119
///         _p_features: &mut MaybeUninit<vk::PhysicalDeviceFeatures>,
120
///     ) -> LayerResult<()> {
121
///         LayerResult::Unhandled
122
///     }
123
/// }
124
///
125
/// let my_instance_hooks: MyInstanceHooks = Default::default();
126
/// assert!(std::ptr::eq(my_instance_hooks.hooks(), &my_instance_hooks));
127
/// assert_eq!(
128
///     MyInstanceHooks::hooked_commands(),
129
///     [LayerVulkanCommand::GetPhysicalDeviceFeatures]
130
/// );
131
/// ```
132
#[proc_macro_attribute]
133
3
pub fn auto_instanceinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream {
134
3
    let original_item: TokenStream2 = item.clone().into();
135
3
    let input = parse_macro_input!(item as ItemImpl);
136
3
    let target_trait = quote!(::vulkan_layer::InstanceInfo);
137
3
    let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| {
138
0
        let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait);
139
0
        let compile_error = e.to_compile_error();
140
0
        quote! {
141
0
            #dummy
142
0
            #compile_error
143
0
        }
144
3
    });
145
3
    quote! {
146
3
        #original_item
147
3
        #to_append
148
3
    }
149
3
    .into()
150
3
}
151
152
/// Derive the implementation of the `vulkan_layer::DeviceInfo` trait from the implementation of the
153
/// `vulkan_layer::DeviceHooks` trait.
154
///
155
/// This attribute macro should be used over an implementation item of the
156
/// `vulkan_layer::DeviceHooks` trait, and will implement the `vulkan_layer::DeviceInfo` trait for
157
/// the type:
158
/// * `DeviceInfo::hooked_commands` returns a list of the overridden methods that appear in the
159
///   implementation item.
160
/// * `DeviceInfo::HooksType` and `DeviceInfo::HooksRefType` are defined as `Self` and `&Self`.
161
/// * `DeviceInfo::hooks` returns `self`.
162
///
163
/// # Examples
164
///
165
/// ```
166
/// use ash::vk;
167
/// use vulkan_layer::{
168
///     auto_deviceinfo_impl, DeviceHooks, DeviceInfo, LayerResult, LayerVulkanCommand,
169
/// };
170
///
171
/// #[derive(Default)]
172
/// struct MyDeviceHooks;
173
///
174
/// #[auto_deviceinfo_impl]
175
/// impl DeviceHooks for MyDeviceHooks {
176
///     fn create_image(
177
///         &self,
178
///         _p_create_info: &vk::ImageCreateInfo,
179
///         _p_allocator: Option<&vk::AllocationCallbacks>,
180
///     ) -> LayerResult<ash::prelude::VkResult<vk::Image>> {
181
///         LayerResult::Unhandled
182
///     }
183
/// }
184
///
185
/// let my_device_hooks: MyDeviceHooks = Default::default();
186
/// assert!(std::ptr::eq(my_device_hooks.hooks(), &my_device_hooks));
187
/// assert_eq!(
188
///     MyDeviceHooks::hooked_commands(),
189
///     [LayerVulkanCommand::CreateImage]
190
/// );
191
/// ```
192
#[proc_macro_attribute]
193
3
pub fn auto_deviceinfo_impl(_: TokenStream, item: TokenStream) -> TokenStream {
194
3
    let original_item: TokenStream2 = item.clone().into();
195
3
    let input = parse_macro_input!(item as ItemImpl);
196
3
    let target_trait = quote!(::vulkan_layer::DeviceInfo);
197
3
    let to_append = details::autoinfo(&input, &target_trait).unwrap_or_else(|e| {
198
0
        let dummy = dummy::dummy_autoinfo_impl(&input.self_ty, &target_trait);
199
0
        let compile_error = e.to_compile_error();
200
0
        quote! {
201
0
            #dummy
202
0
            #compile_error
203
0
        }
204
3
    });
205
3
    quote! {
206
3
        #original_item
207
3
        #to_append
208
3
    }
209
3
    .into()
210
3
}
211
212
/// Declare the required introspection queries for Android given an instantiated
213
/// `vulkan_layer::Global` type.
214
///
215
/// All functions are defined without name mangling, so that they are exported as C symbols in the
216
/// generated dynamic library. This is recommended by
217
/// [the Vulkan loader doc](https://github.com/KhronosGroup/Vulkan-Loader/blob/280997da523951c4016f4ca6af66d58a31e36ab3/docs/LoaderLayerInterface.md#layer-manifest-file-usage:~:text=These%20introspection%20functions%20are%20not%20used%20by%20the%20Khronos%20loader%20but%20should%20be%20present%20in%20layers%20to%20maintain%20consistency.%20The%20specific%20%22introspection%22%20functions%20are%20called%20out%20in%20the%20Layer%20Manifest%20File%20Format%20table):
218
///
219
/// > These introspection functions are not used by the Khronos loader but should be present in
220
/// > layers to maintain consistency. The specific "introspection" functions are called out in the
221
/// > Layer Manifest File Format table.
222
///
223
/// According to the
224
/// [the Vulkan loader doc](https://github.com/KhronosGroup/Vulkan-Loader/blob/280997da523951c4016f4ca6af66d58a31e36ab3/docs/LoaderLayerInterface.md#layer-manifest-file-format), introspection queries include:
225
/// * `vkEnumerateInstanceLayerProperties`
226
/// * `vkEnumerateInstanceExtensionProperties`
227
/// * `vkEnumerateDeviceLayerProperties`
228
/// * `vkEnumerateDeviceExtensionProperties`
229
/// * `vkGetInstanceProcAddr`
230
/// * `vkGetDeviceProcAddr`
231
/// # Examples
232
///
233
/// ```
234
/// # use std::sync::Arc;
235
/// # use vulkan_layer::{StubGlobalHooks, StubInstanceInfo, StubDeviceInfo, Layer, Global, declare_introspection_queries, LayerManifest};
236
/// # use once_cell::sync::Lazy;
237
/// # use ash::{vk, self};
238
/// #
239
/// #[derive(Default)]
240
/// struct MyLayer(StubGlobalHooks);
241
///
242
/// impl Layer for MyLayer {
243
///     // ...
244
/// #     type GlobalHooksInfo = StubGlobalHooks;
245
/// #     type InstanceInfo = StubInstanceInfo;
246
/// #     type DeviceInfo = StubDeviceInfo;
247
/// #     type InstanceInfoContainer = StubInstanceInfo;
248
/// #     type DeviceInfoContainer = StubDeviceInfo;
249
/// #     
250
/// #     fn global_instance() -> impl std::ops::Deref<Target = Global<Self>> + 'static {
251
/// #         static GLOBAL: Lazy<Global<MyLayer>> = Lazy::new(Default::default);
252
/// #         &*GLOBAL
253
/// #     }
254
/// #
255
/// #     fn manifest() -> LayerManifest {
256
/// #         Default::default()
257
/// #     }
258
/// #
259
/// #     fn global_hooks_info(&self) -> &Self::GlobalHooksInfo {
260
/// #         &self.0
261
/// #     }
262
/// #
263
/// #     fn create_instance_info(
264
/// #         &self,
265
/// #         _: &vk::InstanceCreateInfo,
266
/// #         _: Option<&vk::AllocationCallbacks>,
267
/// #         _: Arc<ash::Instance>,
268
/// #         _next_get_instance_proc_addr: vk::PFN_vkGetInstanceProcAddr,
269
/// #     ) -> Self::InstanceInfoContainer {
270
/// #         Default::default()
271
/// #     }
272
/// #
273
/// #     fn create_device_info(
274
/// #         &self,
275
/// #         _: vk::PhysicalDevice,
276
/// #         _: &vk::DeviceCreateInfo,
277
/// #         _: Option<&vk::AllocationCallbacks>,
278
/// #         _: Arc<ash::Device>,
279
/// #         _next_get_device_proc_addr: vk::PFN_vkGetDeviceProcAddr,
280
/// #     ) -> Self::DeviceInfoContainer {
281
/// #         Default::default()
282
/// #     }
283
/// }
284
///
285
/// type MyGlobal = Global::<MyLayer>;
286
/// declare_introspection_queries!(MyGlobal);
287
/// # let _: vk::PFN_vkEnumerateInstanceLayerProperties = vkEnumerateInstanceLayerProperties;
288
/// # let _: vk::PFN_vkEnumerateInstanceExtensionProperties = vkEnumerateInstanceExtensionProperties;
289
/// # let _: vk::PFN_vkEnumerateDeviceLayerProperties = vkEnumerateDeviceLayerProperties;
290
/// # let _: vk::PFN_vkEnumerateDeviceExtensionProperties = vkEnumerateDeviceExtensionProperties;
291
/// # let _: vk::PFN_vkGetInstanceProcAddr = vkGetInstanceProcAddr;
292
/// # let _: vk::PFN_vkGetDeviceProcAddr = vkGetDeviceProcAddr;
293
/// ```
294
#[proc_macro]
295
1
pub fn declare_introspection_queries(item: TokenStream) -> TokenStream {
296
1
    let global_type = parse_macro_input!(item as Type);
297
1
    details::declare_introspection_queries_impl(&global_type)
298
1
        .unwrap_or_else(|e| 
e.to_compile_error()0
)
299
1
        .into()
300
1
}